package com.cloud.pay.controller;

import com.cloud.common.bean.ResultInfo;
import com.cloud.common.support.RemoteLock;
import com.cloud.pay.constant.PayChannelEnum;
import com.cloud.pay.constant.PayStatusEnum;
import com.cloud.pay.constant.RefundStatusEnum;
import com.cloud.pay.constant.ErrorEnum;
import com.cloud.pay.dto.PayParamDTO;
import com.cloud.pay.dto.RefundParamDTO;
import com.cloud.pay.entity.Payment;
import com.cloud.pay.entity.Refund;
import com.cloud.pay.service.PaymentService;
import com.cloud.pay.service.RefundService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;

/**
 * 支付接口
 */
@Slf4j
@RestController
public class PayController {

    @Autowired
    private PaymentService paymentService;

    @Autowired
    private RefundService refundService;

    /**
     * 获取支付二维码
     *
     * @param paramDTO
     * @return ResultInfo
     */
    @PostMapping("/pay/getQrcode")
    public ResultInfo<String> getQrcode(@Valid @RequestBody PayParamDTO paramDTO) {
        Payment payment = new Payment();
        BeanUtils.copyProperties(paramDTO, payment);
        paymentService.save(payment);

        String qrcode = PayChannelEnum.of(payment.getPayChannel()).getPayAdapter().getQrcode(payment);
        return ResultInfo.success().setData(qrcode);
    }

    /**
     * 预支付下单
     *
     * @param paramDTO
     * @return ResultInfo
     */
    @PostMapping("/pay/prepay")
    public ResultInfo<String> prepay(@Valid @RequestBody PayParamDTO paramDTO) {
        Payment payment = new Payment();
        BeanUtils.copyProperties(paramDTO, payment);
        paymentService.save(payment);

        String orderInfo = PayChannelEnum.of(payment.getPayChannel()).getPayAdapter().orderInfo(payment);
        return ResultInfo.success().setData(orderInfo);
    }

    /**
     * 退款
     *
     * @param paramDTO
     * @return ResultInfo
     */
    @PostMapping("/pay/refund")
    public ResultInfo<String> refund(@Valid @RequestBody RefundParamDTO paramDTO) {
        Payment payment = paymentService.getByTradeNo(paramDTO.getAppId(), paramDTO.getTradeNo());
        if (payment == null) {
            return ErrorEnum.NOT_EXIST.resultInfo();
        }
        if (payment.getPayStatus() != PayStatusEnum.PAID.getCode()) {
            return ErrorEnum.NOT_PAID.resultInfo();
        }
        final String key = "Lock:Refund:" + paramDTO.getTradeNo();
        boolean lock = RemoteLock.lock(key, 30000);
        if (!lock) {
            return ResultInfo.manyRequest();
        }
        try {
            Refund refund = refundService.getByTradeNo(paramDTO.getAppId(), paramDTO.getTradeNo());
            if (refund == null || refund.getRefundStatus().intValue() == RefundStatusEnum.UNDO.getCode()) {
                refund.setAppId(payment.getAppId());
                refund.setUserId(payment.getUserId());
                refund.setOrderNo(payment.getOrderNo());
                refund.setTradeNo(payment.getTradeNo());
                refund.setTradeType(payment.getTradeType());
                refund.setRefundNo(paramDTO.getRefundNo());
                refund.setRefundChannel(payment.getPayChannel());
                refund.setRefundMoney(payment.getPayMoney());
                refund.setRefundStatus(RefundStatusEnum.UNDO.getCode());

                boolean successed = PayChannelEnum.of(payment.getPayChannel()).getPayAdapter().refund(refund);
                if (successed) {
                    refund.setRefundStatus(RefundStatusEnum.REFUNDED.getCode());
                    refundService.updateById(refund);
                    return ResultInfo.success();
                }
            }
        } finally {
            RemoteLock.unlock(key);
        }
        return ResultInfo.failure();
    }
}

